﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

namespace SpaceShooter
{
    public class Level
    {
        public Background bg;
        public PlayerShip ps;
        public Boss bs;
        public List<Bullet> playerBullets;
        public List<Bullet> enemyBullets;
        private Texture2D bullet;
        public Enemy[] enemyList;
        public Powerup[] powerupList;
        public int currentPowerup;
        public double[] enemyTime;
        public double[] powerupTime;
        public double currentTime;
        public int currentEnemy;
        public bool active;
        public Vector2 SCREEN_SIZE;
        public double endCount;
        public bool isGameOver;

        public Level(Vector2 screen, Texture2D bgTex, Texture2D playerTex, Texture2D bulletTex,
                     Texture2D bossTex, Powerup[] p_list, Texture2D[] health_lives_tex, int bossType, Enemy[] list, double[] time, double[] p_time)
        {
            SCREEN_SIZE = screen;
            playerBullets = new List<Bullet>();
            playerBullets.Capacity = 500;
            enemyBullets = new List<Bullet>();
            enemyBullets.Capacity = 500;
            bullet = bulletTex;
            enemyList = new Enemy[list.Length];
            enemyTime = new double[time.Length];
            bg = new Background(bgTex, screen);
            ps = new PlayerShip(playerTex, screen);
            ps.healthTex = health_lives_tex[0];
            ps.livesTex = health_lives_tex[1];
            ps.pos = new Vector2(32.0f, 300.0f);
            ps.size = new Vector2(32.0f, 16.0f);
            ps.origin = new Vector2(16.0f, 8.0f);

            powerupList = new Powerup[p_list.Length];
            powerupTime = new double[p_time.Length];

            bs = new Boss(bossTex, SCREEN_SIZE);
            bs.pos = new Vector2(750.0f, 300.0f);
            bs.hp = 100;
            bs.flightPath = bossType;
            powerupList = p_list;
            //powerupList[0] = new Powerup(health_lives_tex[2], screen);

            isGameOver = false;
            for (int i = 0; i < list.Length; i++)
            {
                enemyList[i] = list[i];
                enemyTime[i] = time[i];
            }
            for (int i = 0; i < p_list.Length; i++)
            {
                powerupList[i] = p_list[i];
                powerupTime[i] = p_time[i];
            }

            currentTime = 0;
            currentEnemy = currentPowerup = 0;
            
            active = false;
            endCount = 0;
        }
        public void reset()
        {
            currentTime = 0;
            currentEnemy = currentPowerup = 0;
            isGameOver = false;
        }

        public int update(double elapsedTime)
        {
            if (!active)
            {
                return -1;
            }
            currentTime += elapsedTime;
            bg.update(elapsedTime);
            ps.update(elapsedTime);

            if (currentEnemy < enemyList.Length && enemyTime[currentEnemy] <= currentTime)
            {
                enemyList[currentEnemy].alive = true;
                enemyList[currentEnemy].targetPos = ps.pos - ps.origin;
                if (enemyList[currentEnemy].flightPath == 1)
                {
                    enemyList[currentEnemy].pos.Y += 50.0f;
                }
                currentEnemy++;
                Console.WriteLine("Spawning Enemy # " + currentEnemy);
            }

            //spawning powerups
            if (currentPowerup < powerupList.Length && powerupTime[currentPowerup] <= currentTime)
            {
                powerupList[currentPowerup].alive = true;

                currentPowerup++;
                Console.WriteLine("Spawning Powerup # " + currentPowerup);
            }




            if (currentEnemy >= enemyList.Length)
            {
                bool allDead = true;
                for (int i = 0; i < currentEnemy; i++)
                    allDead = allDead && !enemyList[i].alive;
                if (allDead && endCount==0)
                {
                    // Spawn Boss
                    Console.WriteLine("All Enemies killed, time to spawn boss.");
                    bs.alive = true;
                    endCount = 5.0;
                }
                else if( allDead && endCount>0)
                {
                    if (bs.alive)
                    {
                        int tmp = bs.update(elapsedTime);
                        if (tmp != 0)
                            bossfire(bs, tmp);
                    }
                    else
                    {
                        endCount += elapsedTime;
                    }
                }
                if (endCount > 5)
                    return 1;
            }

            foreach (Bullet b in  playerBullets)
            {
                for (int i = 0; i < currentEnemy; i++)
                {
                    if (b.collides(enemyList[i]))
                    {
                        b.kill();
                        enemyList[i].hp -= b.damage;
                        if (enemyList[i].hp <= 0)
                        {
                            enemyList[i].kill();
                            // score
                        }
                    }
                }
                if( b.collides( bs ) )
                {
                    bs.hp -= b.damage;
                    b.kill();
                }
                if (bs.hp <= 0)
                    bs.kill();
                b.update(elapsedTime);
                if (b.pos.X <= 0)
                    b.kill();
                if (b.pos.X >= SCREEN_SIZE.X)
                    b.kill();
                if (b.pos.Y <= 0)
                    b.kill();
                if (b.pos.Y >= SCREEN_SIZE.Y)
                    b.kill();
            }
            foreach (Powerup p in powerupList)
            {
                if (p.alive == false)
                    continue;
                p.update(elapsedTime);
                //player has hit a poweruplist
                if (ps.collides(p))
                {
                    ps.primaryWeapon = 1; //switch to secondary
                    ps.secondaryWeapon = p.powerup_type; //set secweapon to be different
                    p.alive = false;
                }
            }

            foreach (Bullet b in enemyBullets)
            {
                if (ps.collides(b))
                {
                    // Penalty to player
                    ps.alive = false;
                    b.kill();
                }
                b.update(elapsedTime);
            }
            for (int i = 0; i < currentEnemy; i++)
            {
                if (ps.collides(enemyList[i]))
                {
                    enemyList[i].kill();
                    ps.alive = false;
                    // Penalty to player
                }
                int tmp = enemyList[i].update(elapsedTime);
                if (tmp > 0)
                {
                    fire(enemyList[i], tmp);
                }
                if (enemyList[i].pos.X < -32.0f && enemyList[i].vel.X < 0)
                    enemyList[i].kill();
                if (enemyList[i].pos.X > SCREEN_SIZE.X + 32.0f && enemyList[i].vel.X > 0)
                    enemyList[i].kill();
                if (enemyList[i].pos.Y < -32.0f && enemyList[i].vel.Y < 0)
                    enemyList[i].kill();
                if (enemyList[i].pos.Y > SCREEN_SIZE.Y + 32.0f && enemyList[i].vel.Y > 0)
                    enemyList[i].kill();
            }

            playerBullets.RemoveAll(isDead);
            enemyBullets.RemoveAll(isDead);
            if (isGameOver)
                return -1;
            return 0;
        }

        public void draw(SpriteBatch sb)
        {
            if (!active)
                return;
            ps.draw(sb);
            
            if (bs.alive)
                bs.draw(sb);

            for (int i = 0; i < currentEnemy; i++)
            {
                if (enemyList[i].alive)
                {
                    enemyList[i].draw(sb);
                }
            }

            for (int i = 0; i < currentPowerup; i++)
            {
                if (powerupList[i].alive)
                    powerupList[i].draw(sb);
            }

            foreach (Bullet b in playerBullets)
            {
                b.draw(sb);
            }
            foreach (Bullet b in enemyBullets)
            {
                b.draw(sb);
            }
            bg.draw(sb);
        }

        public void start()
        {
            active = true;
            ps.alive = true;
            currentTime = 0.0;
        }

        public void stop()
        {
            active = false;
            ps.alive = false;
            for (int i = 0; i < enemyList.Length; i++)
            {
                enemyList[i].kill();
            }
            for (int i = 0; i < powerupList.Length; i++)
                powerupList[i].kill();

            playerBullets.RemoveAll(isTrue);
            enemyBullets.RemoveAll(isTrue);
        }

        private void fire(Enemy e, int type)
        {
            Vector2 facing;
            if (type == 1)
            {
                facing = new Vector2(-1.0f, 0.0f);
            }
            else
            {
                facing = new Vector2((float)Math.Cos(e.angle), (float)Math.Sin(e.angle));
            }
            Bullet b = new Bullet(bullet, SCREEN_SIZE);
            b.pos = e.pos;
            b.vel = facing * 175.0f;
            b.alive = true;
            enemyBullets.Add(b);
        }

        private void bossfire(Enemy e, int type)
        {
            Bullet b;
            switch (type)
            {
                case 1:
                    b = new Bullet(bullet, SCREEN_SIZE);
                    b.pos = e.pos - e.origin + new Vector2( 6, 22);
                    b.vel = new Vector2(-175.0f, 0.0f);
                    b.alive = true;
                    enemyBullets.Add(b);
                    b = new Bullet(bullet, SCREEN_SIZE);
                    b.pos = e.pos - e.origin + new Vector2(6, 87);
                    b.vel = new Vector2(-175.0f, 0.0f);
                    b.alive = true;
                    enemyBullets.Add(b);
                    break;
                case 2:
                    b = new Bullet(bullet, SCREEN_SIZE);
                    b.pos = e.pos;
                    b.vel = new Vector2(-175.0f, 0.0f);
                    b.alive = true;
                    enemyBullets.Add(b);
                    b = new Bullet(bullet, SCREEN_SIZE);
                    b.pos = e.pos;
                    b.vel = new Vector2(-175.0f * (float)Math.Cos(0.52), 175.0f * (float)Math.Sin(0.52));
                    b.alive = true;
                    enemyBullets.Add(b);
                    b = new Bullet(bullet, SCREEN_SIZE);
                    b.pos = e.pos;
                    b.vel = new Vector2(-175.0f * (float)Math.Cos(0.52), -175.0f * (float)Math.Sin(0.52));
                    b.alive = true;
                    enemyBullets.Add(b);
                    break;
                case 3:
                    Vector2 target = ps.pos - e.pos;
                    target.Normalize();
                    target *= 175.0f;
                    b = new Bullet(bullet, SCREEN_SIZE);
                    b.pos = e.pos;
                    b.vel = target;
                    b.alive = true;
                    enemyBullets.Add(b);
                    break;
                case 4:
                    b = new Bullet(bullet, SCREEN_SIZE);
                    b.pos = e.pos;
                    b.vel = new Vector2(-175.0f * (float)Math.Cos(0.26 + e.angle), 175.0f * (float)Math.Sin(0.26+e.angle));
                    b.alive = true;
                    enemyBullets.Add(b);
                    b = new Bullet(bullet, SCREEN_SIZE);
                    b.pos = e.pos;
                    b.vel = new Vector2(-175.0f * (float)Math.Cos(-0.26+e.angle), 175.0f * (float)Math.Sin(-0.26+e.angle));
                    b.alive = true;
                    enemyBullets.Add(b);
                    b = new Bullet(bullet, SCREEN_SIZE);
                    b.pos = e.pos;
                    b.vel = new Vector2(-175.0f * (float)Math.Cos(0.78+e.angle), 175.0f * (float)Math.Sin(0.78 + e.angle));
                    b.alive = true;
                    enemyBullets.Add(b);
                    b = new Bullet(bullet, SCREEN_SIZE);
                    b.pos = e.pos;
                    b.vel = new Vector2(-175.0f * (float)Math.Cos(-0.78+e.angle), 175.0f * (float)Math.Sin(-0.78 + e.angle));
                    b.alive = true;
                    enemyBullets.Add(b);
                    break;
            }
        }

        public void shoot()
        {
            Bullet b;
            if (ps.primaryWeapon == 0)
            {
                switch (ps.weaponType)
                {
                    case 0:
                        b = new Bullet(bullet, SCREEN_SIZE);
                        b.pos = ps.pos + new Vector2(16.0f, 0.0f);
                        b.vel = new Vector2(375.0f, 0.0f);
                        b.alive = true;
                        playerBullets.Add(b);
                        ps.fireTimer += 0.25;
                        break;
                    case 1:
                        b = new Bullet(bullet, SCREEN_SIZE);
                        b.pos = ps.pos + new Vector2(16.0f, 0.0f);
                        b.vel = new Vector2(225.0f, 0.0f);
                        b.alive = true;
                        playerBullets.Add(b);
                        b = new Bullet(bullet, SCREEN_SIZE);
                        b.pos = ps.pos + new Vector2(16.0f, 0.0f);
                        b.vel = new Vector2(225.0f, 35.0f);
                        b.alive = true;
                        playerBullets.Add(b);
                        b = new Bullet(bullet, SCREEN_SIZE);
                        b.pos = ps.pos + new Vector2(16.0f, 0.0f);
                        b.vel = new Vector2(225.0f, -35.0f);
                        b.alive = true;
                        playerBullets.Add(b);
                        ps.fireTimer += 0.55;
                        break;
                    default:
                        b = new Bullet(bullet, SCREEN_SIZE);
                        b.pos = ps.pos + new Vector2(16.0f, 0.0f);
                        b.vel = new Vector2(175.0f, 0.0f);
                        b.alive = true;
                        playerBullets.Add(b);
                        ps.fireTimer += 0.25;
                        break;
                }
            }
            else
            {
                switch (ps.secondaryWeapon)
                {
                    case 0:
                        b = new Bullet(bullet, SCREEN_SIZE);
                        b.pos = ps.pos + new Vector2(16.0f, 0.0f);
                        b.vel = new Vector2(375.0f, 0.0f);
                        b.alive = true;
                        playerBullets.Add(b);
                        ps.fireTimer += 0.25;
                        ps.primaryWeapon = 0;
                        break;
                    case 1:
                        b = new Bullet(bullet, SCREEN_SIZE);
                        b.pos = ps.pos + new Vector2(16.0f, 0.0f);
                        b.vel = new Vector2(375.0f, 10.0f);
                        b.alive = true;
                        playerBullets.Add(b);
                        b = new Bullet(bullet, SCREEN_SIZE);
                        b.pos = ps.pos + new Vector2(16.0f, 0.0f);
                        b.vel = new Vector2(375.0f, 0.0f);
                        b.alive = true;
                        playerBullets.Add(b);
                        b = new Bullet(bullet, SCREEN_SIZE);
                        b.pos = ps.pos + new Vector2(16.0f, 0.0f);
                        b.vel = new Vector2(375.0f, -10.0f);
                        b.alive = true;
                        playerBullets.Add(b);
                        ps.fireTimer += 0.25;
                        break;
                    case 2:
                        b = new Bullet(bullet, SCREEN_SIZE);
                        b.pos = ps.pos + new Vector2(16.0f, 0.0f);
                        b.vel = new Vector2(400.0f, 0.0f);
                        b.alive = true;
                        playerBullets.Add(b);
                        ps.fireTimer += 0.60;
                        break;
                    case 3:
                        b = new Bullet(bullet, SCREEN_SIZE);
                        b.pos = ps.pos + new Vector2(16.0f, 0.0f);
                        b.vel = new Vector2(375.0f, 0.0f);
                        b.alive = true;
                        playerBullets.Add(b);
                        b = new Bullet(bullet, SCREEN_SIZE);
                        b.pos = ps.pos + new Vector2(16.0f, 10.0f);
                        b.vel = new Vector2(375.0f, 0.0f);
                        b.alive = true;
                        playerBullets.Add(b);
                        b = new Bullet(bullet, SCREEN_SIZE);
                        b.pos = ps.pos + new Vector2(16.0f, -10.0f);
                        b.vel = new Vector2(375.0f, 0.0f);
                        b.alive = true;
                        playerBullets.Add(b);
                        ps.fireTimer += 0.25;
                        break;
                    default:
                        break;
                }
            }
            
        }

        private static bool isDead(Bullet b)
        {
            return !b.alive;
        }

        private static bool isTrue( Bullet b)
        {
            return true;
        }
    }

    public class GameOverScreen
    {
        Texture2D bg;
        Vector2 SCREEN_SIZE;
        ContentManager c;
        public bool restart = false;
        public GameOverScreen(Texture2D b_g, Vector2 screen, ContentManager content)
        {
            bg = b_g;
            SCREEN_SIZE = screen;
            c = content;
        }

        public bool getRestart()
        {
            return restart;
        }

        public void update()
        {
            KeyboardState ks = Keyboard.GetState();
            if (ks.IsKeyDown(Keys.R))
            {
                restart = true;
            }
        }
        public void draw(SpriteBatch sb)
        {
            sb.Draw(bg, new Rectangle(0, 0, 800, 600), Color.Black);
            
        }

    }
}
